Skip to content

Support Ruff 0.16 suppression directives - #12

Merged
leynos merged 8 commits into
mainfrom
support-new-ruff-suppressions
Aug 20, 2026
Merged

Support Ruff 0.16 suppression directives#12
leynos merged 8 commits into
mainfrom
support-new-ruff-suppressions

Conversation

@leynos

@leynos leynos commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Summary

This branch extends lint-suppression-without-explanation to recognize Ruff
0.16 line-level, file-level, and range suppression directives, so diagnostic
suppression continues to carry an auditable reason. It locks Ruff 0.16.0 to
exercise that compatibility contract in repository gates.

The parser accepts rule codes and preview rule names, documented whitespace
(including before selector brackets), and trailing commas. It requires a
complete selector list, rejects case-invalid and misplaced forms, and matches
Ruff directives case-sensitively. File-level and range directives must occupy
standalone comments. ruff: enable[...] ends a suppression range, so it
neither requires a reason nor counts as prose explaining a later directive.

The user and developer guides record the grammar, aliases, and explanation
precedence. The v0.3.0 migration guide shows maintainers how to update newly
flagged directives. Hypothesis properties generate directive kinds, selectors,
whitespace, separators, trailing commas, explanation placements, and neutral
range terminators. The property suite has its own module to keep test files
within the repository's file-size limit.

Review walkthrough

Validation

  • make check-fmt: passed.
  • make test: passed; 322 passed, 1 skipped.
  • make typecheck: passed.
  • make lint: passed; Ruff, 100% interrogate coverage and PyPy-backed Pylint (10.00/10) were clean.
  • make audit: passed with no known vulnerabilities.
  • make markdownlint: passed, including the en-GB-oxendict spelling gate.
  • make nixie: passed; all Mermaid diagrams validated.
  • mbake validate Makefile: passed.

References

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @leynos, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f44d76a6-4248-4963-bc3e-a7b56844352f

📥 Commits

Reviewing files that changed from the base of the PR and between e5f411e and 29c3639.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • df12_python_lints/suppressions.py
  • docs/developers-guide.md
  • docs/users-guide.md
  • tests/test_properties.py
  • tests/test_suppression_properties.py
  • tests/test_suppressions.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • leynos/pylint-pypy-shim (auto-detected)

Included review availability: 2 reviews are currently available. Based on recent review activity, included reviews refill at 3 per hour.


Summary

Extend lint-suppression-without-explanation to support Ruff 0.16 suppression directives.

  • Recognize ignore, file-ignore, disable, and enable directives.
  • Support rule codes, preview rule names, documented whitespace, bracket spacing, and trailing commas.
  • Require standalone comments for file-level and range directives.
  • Treat directive matching as case-sensitive.
  • Keep ruff: enable[...] neutral.
  • Recognize explanations on trailing physical and preceding logical lines.
  • Document the checker contract and Ruff grammar.
  • Add regression and property-based tests.
  • Lock Ruff to 0.16.0.

Validate formatting, linting, type checking, tests, auditing, Markdown, Mermaid, and Makefile checks. The suite passes 322 tests, with one skipped test.

Walkthrough

Update suppression parsing for Ruff directives and rule-list formats. Require preceding explanations to contain prose beyond directives. Document and test the syntax, standalone-comment rules, and neutral behaviour of ruff: enable.

Changes

Suppression validation

Layer / File(s) Summary
Expand directive parsing
df12_python_lints/suppressions.py, tests/test_suppressions.py, tests/test_suppression_properties.py, docs/developers-guide.md, docs/users-guide.md
Recognise Ruff ignore, file-ignore, disable, and enable directives with validated rule lists. Cover spacing, trailing commas, case sensitivity, standalone comments, and generated syntax variants.
Refine explanation detection
df12_python_lints/suppressions.py, tests/test_suppressions.py, tests/test_suppression_properties.py, docs/users-guide.md
Require prose beyond directives for preceding explanations. Treat standalone Ruff enable directives as neutral and prevent them from explaining later suppressions.
Migrate suppression property tests
tests/test_properties.py, tests/test_suppression_properties.py
Remove the former suppression tokenisation tests and add dedicated property tests for Ruff, noqa, and Pylint suppression classification.

Possibly related PRs

Poem

Parse Ruff rules with care,
Keep directives clean and spare.
Prose must stand apart,
enable ends its part,
Tests guard every pair.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 warning, 4 inconclusive)

Check name Status Explanation Resolution
User-Facing Documentation ⚠️ Warning The users guide documents the Ruff directives, but the PR adds new C9106 behaviour and updates no n+1 migration guide; docs/migration-0.2.0.md remains unchanged. Add a Ruff-suppression migration section to the applicable n+1 guide, including newly flagged directives, explanation requirements, and range-terminator behaviour.
Testing (Overall) ❓ Inconclusive The working tree has no diff, so the pull-request changes are not yet evidenced against a base revision. Provide the pull-request base revision or a usable commit diff, then reassess the changed tests.
Developer Documentation ❓ Inconclusive The PR adds developer-guide documentation for the changed suppression grammar, but evidence is still needed for tooling requirements and any design or roadmap artefacts. Inspect the actual diff and repository planning documents to confirm that all changed internal APIs, tooling requirements, and execution plans are documented.
Testing (Compile-Time / Ui) ❓ Inconclusive The PR changes Python lint-checker behaviour, not Rust or TypeScript compile-time behaviour; focused unit and property tests assert diagnostic symbols and suppression classification, but snapshot a... Confirm whether this repository requires snapshots for linter diagnostic output.
Performance And Resource Use ❓ Inconclusive I have not completed the performance investigation. Inspect the changed parser and its realistic input bounds before deciding.
✅ Passed checks (15 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Module-Level Documentation ✅ Passed Every Python module in the branch has a module docstring; the new test module documents suppression pragma classification, and suppressions.py documents purpose, use and explanation handling.
Testing (Unit And Behavioural) ✅ Passed The added tests exercise process_tokens at the checker boundary, cover valid, malformed, case-invalid, standalone, explanation, and neutral-enable cases, and add Hypothesis invariants; no explicit...
Testing (Property / Proof) ✅ Passed The parser introduces input-grammar and explanation-precedence invariants, and the PR adds substantive Hypothesis properties over directive kinds, selectors, whitespace, separators, prose placement...
Unit Architecture ✅ Passed The changed code parses in-memory tokens with compiled regexes and emits checker diagnostics only at the explicit Pylint boundary; it adds no I/O, global state, hidden dependencies, or mixed side-e...
Domain Architecture ✅ Passed The change remains isolated to suppression parsing and tests; it adds no transport, persistence, framework, filesystem, or vendor-boundary dependency to domain logic.
Observability ✅ Passed The diff changes static suppression parsing, tests, and documentation only; it adds no production operational path or new throughput, latency, error, queue, resource, logging, metric, tracing, or a...
Security And Privacy ✅ Passed The changed files add only local suppression parsing, tests, documentation, and a Ruff lock entry; no secrets, trust-boundary checks, privileged access, unsafe sinks, or sensitive-data exposure wer...
Concurrency And State ✅ Passed The change is limited to stateless suppression parsing and tests; it adds no shared mutable state, async tasks, locks, ordering protocol, or concurrent execution.
Architectural Complexity And Maintainability ✅ Passed The PR adds focused regex constants and a small _Comment context type, while moving suppression properties to a feature-specific module; no speculative layers, dependencies, cycles, or parallel ext...
Rust Compiler Lint Integrity ✅ Passed The PR changes only Python, Markdown, and uv.lock files; base and HEAD contain no Cargo manifests or .rs files, and no Rust lint or clone changes were introduced.
Title check ✅ Passed Accept the title because it clearly identifies the main change: support for Ruff 0.16 suppression directives.
Description check ✅ Passed Accept the description because it directly explains the Ruff directive support, tests, documentation, and validation changes.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch support-new-ruff-suppressions

Comment @coderabbitai help to get the list of available commands.

codescene-access[bot]

This comment was marked as outdated.

@leynos
leynos marked this pull request as ready for review July 27, 2026 19:53
chatgpt-codex-connector[bot]

This comment was marked as resolved.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@pandalump

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

codescene-access[bot]

This comment was marked as outdated.

codescene-access[bot]

This comment was marked as outdated.

@buzzybee-df12

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

coderabbitai[bot]

This comment was marked as resolved.

leynos and others added 7 commits August 17, 2026 01:47
Require explanations for Ruff line, file, and range suppression
directives, including rule-name selectors and the documented spacing and
trailing-comma variants.

Keep range terminators neutral, extend regression coverage for the full
comment grammar, document the expanded rule, and lock Ruff 0.16.0 so the
compatibility contract is exercised by the project gates.
Recognize Ruff suppression and range directives when whitespace separates
the keyword from its selector bracket. Keep spaced `enable` terminators
neutral so they cannot explain a following suppression accidentally.

Add regressions for line-level, file-level and range forms accepted by
Ruff 0.16.0.
Describe Ruff range terminators and the complete suppression grammar in
the user and developer guides. Add generated coverage for grammar
variants, explanation precedence, and neutral enable directives.
Treat Ruff directives as case-sensitive and require file-level and range
directives to occupy standalone comments. Avoid C9106 false positives for
forms that Ruff itself does not recognize as suppressions.
Recognize range terminators even when trailing prose follows them. Prevent
the entire comment from explaining a later suppression and add a regression
that distinguishes neutral handling from ignoring `enable` altogether.
Require complete selector lists before classifying Ruff suppressions, and
cover malformed, case-invalid, and misplaced forms. Move the generated
suppression properties into their own module so the rebased suite remains
within the project's file-size limit.
@leynos
leynos force-pushed the support-new-ruff-suppressions branch from b37a9fc to 29c3639 Compare August 17, 2026 00:08
codescene-access[bot]

This comment was marked as outdated.

@wafflecat-df12

Copy link
Copy Markdown

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@leynos

leynos commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

docs/users-guide.md (1)

134-136: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Correct the C9106 directive list.
Remove ruff: enable from Line 136. It terminates a suppression range and does

not emit C9106, which contradicts Lines 144-146.
Triage: [type:docstyle]

🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs/users-guide.md around lines 134 - 136, Update the C9106 directive list
in the lint suppression documentation by removing ruff: enable, while
retaining the other listed pragmas and keeping the documented suppression-range
behavior consistent with the later guidance.

docs/developers-guide.md (1)

38-45: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Document file-level noqa alias restrictions in both guides.
State that ruff: noqa and flake8: noqa require standalone comments. State that their prefixes are case-sensitive, while noqa and inline noqa are case-insensitive.

  • Update docs/developers-guide.md:38-45.
  • Update docs/users-guide.md:140-142.
    Triage: [type:docstyle]
🤖 Detailed instructions

Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @docs/developers-guide.md around lines 38 - 45, Update the documentation
describing file-level noqa aliases in docs/developers-guide.md:38-45 and
docs/users-guide.md:140-142. State that ruff: noqa and flake8: noqa require
standalone comments, their prefixes are case-sensitive, and noqa plus inline
noqa forms are case-insensitive.

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- docs/users-guide.md: relevant lines ---'
nl -ba docs/users-guide.md | sed -n '125,155p'

printf '%s\n' '--- docs/developers-guide.md: relevant lines ---'
nl -ba docs/developers-guide.md | sed -n '30,60p'

printf '%s\n' '--- directive parsing implementation ---'
ast-grep outline df12_python_lints/suppressions.py --items all --view expanded
rg -n -C 5 -P 'ruff:|flake8:|noqa|_directive_symbols|is_standalone' df12_python_lints/suppressions.py

Length of output: 919


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_lines() {
  file="$1"
  start="$2"
  end="$3"
  printf '%s\n' "--- ${file}:${start}-${end} ---"
  sed -n "${start},${end}p" "$file" | awk -v n="$start" '{ printf "%d: %s\n", n++, $0 }'
}

show_lines docs/users-guide.md 125 155
show_lines docs/developers-guide.md 30 60

printf '%s\n' '--- matching implementation locations ---'
grep -n -E -C 5 'ruff:|flake8:|noqa|_directive_symbols|is_standalone' df12_python_lints/suppressions.py || true

printf '%s\n' '--- implementation context ---'
grep -n -E '_directive_symbols|RUFF|NOQA|FLAKE8' df12_python_lints/suppressions.py || true

Length of output: 10193


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- suppression documentation in both guides ---'
grep -n -i -E -C 4 'ruff:[[:space:]]*noqa|flake8:[[:space:]]*noqa|standalone comment|case-sensitive|case-insensitive|suppression' \
  docs/users-guide.md docs/developers-guide.md || true

printf '%s\n' '--- alias-related tests ---'
grep -n -i -E -C 4 'ruff:[[:space:]]*noqa|flake8:[[:space:]]*noqa|standalone|case-sensitive|case-insensitive' \
  tests/test_suppressions.py tests/test_suppression_properties.py 2>/dev/null || true

printf '%s\n' '--- regex behaviour for requested alias forms ---'
python - <<'PY'
from df12_python_lints import suppressions

cases = (
    ("# ruff: noqa", True),
    ("# Ruff: noqa", True),
    ("value = 1  # ruff: noqa", False),
    ("# flake8: noqa", True),
    ("# Flake8: noqa", True),
    ("value = 1  # flake8: noqa", False),
    ("value = 1  # NOQA", False),
)
for text, standalone in cases:
    comment = suppressions._Comment(text, standalone)
    print(f"{text!r}, standalone={standalone}: {suppressions._directive_symbols(comment)!r}")
PY

Length of output: 14127


@leynos

Mark the ruff: enable finding as resolved.

  • docs/users-guide.md Lines 134-136 no longer list ruff: enable as a C9106 suppression directive.
  • Lines 147-149 correctly state that ruff: enable[...] terminates a range and does not emit C9106.

Keep the file-level noqa alias finding open.

  • The requested wording exists in docs/users-guide.md Lines 140-145 and docs/developers-guide.md Lines 92-95.
  • The wording does not match the current implementation.
  • df12_python_lints/suppressions.py applies re.IGNORECASE to _LINT_DIRECTIVE.
  • The matcher also detects noqa inside inline and mixed-case aliases.

The current checker emits C9106 for all of these forms:

# Ruff: noqa
value = 1  # ruff: noqa
# Flake8: noqa
value = 1  # flake8: noqa

Update the parser and add regression tests to enforce the documented standalone and case-sensitive alias rules. Alternatively, revise both guides to describe the current behaviour.


🧠 Learnings used
Learnt from: leynos
Repo: leynos/dakar PR: 0
File: :0-0
Timestamp: 2026-08-16T12:38:29.454Z
Learning: For `leynos/dakar` pull request reviews, treat reported warnings as required work. Keep observability, code safety, documentation, and validation coverage in scope. If a valid finding is out of scope, identify an existing GitHub issue or propose a focused GitHub follow-up issue.

You are interacting with an AI system.

@leynos

leynos commented Aug 20, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai Have the following now been resolved?

df12_python_lints/suppressions.py (1)

54-83: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Split Ruff directive matching by syntax. Make the ruff: branch case-sensitive and own-line only so # RUFF: ignore[...] and inline ruff: file-ignore[...] / ruff: disable[...] do not emit C9106. Add negative regressions for those forms.

🤖 Detailed instructions

Use a wyvern agent team to verify each finding against the current code and only fix it if needed. Fix any documentation issues using a scribe agent team. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Use a scrutineer agent for execution of tests and summarizing the results.

In @df12_python_lints/suppressions.py around lines 54 - 83, Split Ruff directive
detection in _DIRECTIVE_ONLY_SEGMENT so the ruff: branch is case-sensitive and
matches only when the directive occupies its own line. Ensure uppercase “RUFF”
and inline file-ignore or disable directives are not classified as C9106, and
add negative regression tests covering these forms.

@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- PR head and changed files ---'
git status --short
git diff --name-only HEAD^ HEAD || true

printf '%s\n' '--- suppressions module outline ---'
ast-grep outline df12_python_lints/suppressions.py --items all --view expanded

printf '%s\n' '--- directive parsing implementation ---'
nl -ba df12_python_lints/suppressions.py | sed -n '35,115p'

printf '%s\n' '--- Ruff-related regression tests ---'
rg -n -i -C 5 'ruff|file-ignore|disable|standalone|case-sensitive|invalid' \
  tests/test_suppressions.py tests/test_suppression_properties.py 2>/dev/null || true

printf '%s\n' '--- relevant PR diff ---'
git diff HEAD^ HEAD -- df12_python_lints/suppressions.py tests/test_suppressions.py tests/test_suppression_properties.py || true

Length of output: 2701


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- parser patterns and classification ---'
sed -n '45,140p' df12_python_lints/suppressions.py

printf '%s\n' '--- standalone comment collection ---'
sed -n '160,225p' df12_python_lints/suppressions.py

printf '%s\n' '--- exact negative Ruff regressions ---'
rg -n -C 6 -e 'RUFF:' -e 'ruff: file-ignore' -e 'ruff: disable' \
  tests/test_suppressions.py tests/test_suppression_properties.py 2>/dev/null || true

printf '%s\n' '--- test classes and nearby Ruff cases ---'
ast-grep outline tests/test_suppressions.py --items all --view expanded
rg -n -C 4 -i 'invalid.*ruff|ruff.*invalid|standalone.*ruff|ruff.*standalone' \
  tests/test_suppressions.py tests/test_suppression_properties.py 2>/dev/null || true

Length of output: 14300


@leynos Mark this finding as resolved.

df12_python_lints/suppressions.py now separates the Ruff syntax:

  • _RUFF_INLINE_DIRECTIVE matches only ruff: ignore[...].
  • _RUFF_STANDALONE_DIRECTIVE matches ruff: file-ignore[...] and ruff: disable[...] only when _Comment.is_standalone is true.
  • Ruff patterns have no case-insensitive flag. Therefore, # RUFF: ignore[...] does not emit C9106.
  • _DIRECTIVE_ONLY_SEGMENT uses (?-i:ruff...) to keep Ruff directive recognition case-sensitive.

tests/test_suppressions.py includes negative regressions for:

  • x = 1 # RUFF: ignore[F841]
  • x = 1 # ruff: file-ignore[F841]
  • x = 1 # ruff: disable[F841]

The test suite was not executed in this sandbox. Static inspection confirms that the implementation and regression tests meet the finding requirements.

You are interacting with an AI system.

Document the v0.3.0 suppression-comment requirements so projects can update
newly recognised Ruff and Flake8 pragmas without losing their rationale.
Explain accepted syntax and the neutral `ruff: enable[...]` range terminator.
@leynos
leynos merged commit ff31021 into main Aug 20, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants